package org.store.dao;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.annotation.Transactional;
import org.store.domain.Category;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CategoryDao extends AbstractDao<Category> {

    public Map<Long, Category> getCategoryMap() throws DaoException {
        try {
            List<Category> categories = jdbcTemplate.query("select * from category", MAPPER);
            return cohereCategories(saveCategoryToMap(categories));
        } catch (DataAccessException e) {
            throw new DaoException("Cannot get all categories", e);
        }
    }

    private Map<Long, Category> cohereCategories(Map<Long, Category> map) {
        for (Category category : map.values()) {
            Category parent = map.get(category.getParentId());
            if (parent == null)
                continue;
            parent.addChild(category);
        }
        return map;
    }

    protected Map<Long, Category> saveCategoryToMap(List<Category> categories) {
        if (categories.isEmpty())
            throw new IllegalArgumentException("Lst of categories is Empty");

        Map<Long, Category> categoryMap = new HashMap<>();
        for (Category category : categories) {
            categoryMap.put(category.getId(), category);
        }
        return categoryMap;
    }

    @Override
    @Transactional
    public Category save(Category category) throws DaoException {
        if (category == null)
            throw new IllegalArgumentException("Category cannot be null");
        try {
            long id = jdbcTemplate.queryForLong("insert into category (name, parent_id) values(?,?) returning category_id",
                    category.getName(), category.getParentId());
            category.setId(id);
            return category;
        } catch (DataAccessException e) {
            throw new DaoException("Cannot save category with id = " + category.getId(), e);
        }
    }

    @Override
    public Category getById(long id) throws DaoException {
        try {
                   return jdbcTemplate.queryForObject("select category_id, name, parent_id from category where category_id = ?", MAPPER, id);
               } catch (DataAccessException e) {
                   throw new DaoException("Cannot get category with id = " + id, e);
               }
    }


    @Override
    public boolean delete(Category category) throws DaoException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Category saveOrUpdate(Category category) throws DaoException {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<Category> saveAll(List<Category> e) throws DaoException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isExists(long id) throws DaoException {
        throw new UnsupportedOperationException();
    }

    private static final RowMapper<Category> MAPPER = new RowMapper<Category>() {
        public Category mapRow(ResultSet rs, int rowNum) throws SQLException {
            Category category = new Category(rs.getString("name"), rs.getLong("parent_id"));
            category.setId(rs.getLong("category_id"));
            return category;
        }
    };
}
